/*
**  Copyright (c) 2014 Michael Liu(michael.liu.point@gmail.com).
**
**  Project: Gateway Unified Management Platform
**  File:    mtk7620.c
**  Author:  Michael
**  Date:    06/22/2014
**
**  Purpose:
**    MTK7620 depend function implement.
*/

/* Include files. */

#include "common.h"
#include "osdep.h"

#include <fcntl.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sysinfo.h>
#include <sys/time.h>

#include <net/if.h>
#include <net/if_arp.h>
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/if_vlan.h>
#include <linux/sockios.h>

/* Macro constant definitions. */

#define RESOLV_CONF_FILE	"/etc/resolv.conf"

#define ETHTOOL_GLINK                0x0000000a /* Get link status (ethtool_value) */

/* Type definitions. */

/* for passing single values */
struct ethtool_value {
        __u32   cmd;
        __u32   data;
};

/* Local function declarations. */

extern int br_add_bridge(int br_socket_fd, const char *brname);
extern int br_del_bridge(int br_socket_fd, const char *brname);
extern int br_add_interface(int br_socket_fd, const char *bridge, const char *dev);
extern int br_del_interface(int br_socket_fd, const char *bridge, const char *dev);
extern int br_set_stp_state(int br_socket_fd, const char *br, int stp_state);
extern int br_set_bridge_forward_delay(int br_socket_fd, const char *br, int delay);

/* Macro API definitions. */

/* Global variable declarations. */

/*
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!                                                                                                !!
!!     MUST ADD NULL for the last parameter                                       !!
!!     eg: os_dep_do_system_raw(0, NULL, "ls","/home", NULL);                                            !!
!!                                                                                                !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
int os_dep_do_system_raw(unsigned char wait, tos_dep_task * child, const char *exec_file, ...)
{

	pid_t pid;
	int status;
	sigset_t chldmask, savemask;

	if (exec_file == NULL) {
		return (-1);
	}

	/* now block SIGCHLD */
	sigemptyset(&chldmask);
	sigaddset(&chldmask, SIGCHLD);
	if (sigprocmask(SIG_BLOCK, &chldmask, &savemask)) {
		return (-2);
	}

	pid = fork();
	if (pid < 0) {
		/* Error. */
		return (-3);
	} else if (pid == 0) {
		/* Child. */
		int n;
		char **argv;
		char **p;
		va_list args;

		n = 1;
		va_start(args, exec_file);
		for (; va_arg(args, char *);) {
			++n;
		}
		va_end(args);

		p = argv = (char **)malloc((n + 1) * sizeof(char *));

		p[0] = (char *)exec_file;

		va_start(args, exec_file);
		for (; n--;) {
			*++p = va_arg(args, char *);
		}
		va_end(args);
		*p = NULL;

		n = execvp(exec_file, (void *)argv);
		/* on error */
		free(argv);
		exit(n);

	} else {
		/* Parent. */
		if (child) {
			*child = pid;
		}

		if (wait) {
			while (waitpid(pid, &status, 0) < 0) {
				if (errno != EINTR) {
					return (-1);
				}
			}
		} else {
			sigprocmask(SIG_SETMASK, &savemask, NULL);
			return (0);
		}
	}

	sigprocmask(SIG_SETMASK, &savemask, NULL);
	return WEXITSTATUS(status);

}

int os_dep_wait(tos_dep_task * task, int *status, int option)
{

	pid_t pid;
	int wait_status;

	do {
		pid = waitpid(*task, &wait_status, option);
		if (pid < 0) {
			if (errno != EINTR) {
				*task = pid;
				return (-1);
			}
			usleep(1000);
			continue;
		}
	} while (pid < 0);

	if (task != NULL) {
		*task = pid;
	}

	if (status != NULL) {
		*status = wait_status;
	}

	return (0);

}

int os_dep_killall(const char *exec_file, const char *signal)
{
	int rc = 0;

	if (exec_file != NULL) {
		rc = os_dep_do_system("killall", signal, exec_file, NULL);
	}
	return (0);
}

int os_dep_kill(tos_dep_task child, int signal)
{
	return (kill(child, signal));
}

e_ret os_dep_create_bridge(tdp_if * dp_if)
{
	e_ret ret;
	int rc;
	int sockfd;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	rc = br_add_bridge(sockfd, dp_if->name);
	switch (rc) {
	case 0:
		ret = eRET_SUCCESS;
		break;

	case EEXIST:
		sysmgr_dbg("interface [%s] already exist.\n", dp_if->name);
		ret = eRET_ALREADY_EXIST;
		break;

	default:
		sysmgr_err("br_add_bridge() failed, err: %d,[%s]\n", rc, strerror(rc));
		ret = eRET_FAILURE;
		break;
	}

	/* Disable STP */
	br_set_stp_state(sockfd, dp_if->name, eBOOL_FALSE);

	/* no forward delay */
	br_set_bridge_forward_delay(sockfd, dp_if->name, 0);

	close(sockfd);

	return (ret);

}

e_ret os_dep_destroy_bridge(tdp_if * dp_if)
{
	e_ret ret;
	int rc;
	int sockfd;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	rc = br_del_bridge(sockfd, dp_if->name);
	switch (rc) {
	case 0:
		ret = eRET_SUCCESS;
		break;

	case ENXIO:
		sysmgr_dbg("interface [%s] not exist.\n", dp_if->name);
		ret = eRET_NOT_EXIST;
		break;

	case EBUSY:
		sysmgr_dbg("interface [%s] still up.\n", dp_if->name);
		ret = eRET_INVALID_STATE;
		break;

	default:
		sysmgr_err("br_del_bridge() failed, err: %d,[%s]\n", rc, strerror(rc));
		ret = eRET_FAILURE;
		break;
	}

	close(sockfd);

	return (ret);

}

e_ret os_dep_add_bridge_member(tdp_if * dp_if, tdp_if * member_if)
{
	e_ret ret;
	int rc;
	int sockfd;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	rc = br_add_interface(sockfd, dp_if->name, member_if->name);
	switch (rc) {
	case 0:
		ret = eRET_SUCCESS;
		break;

	case ENODEV:
		sysmgr_dbg("member interface [%s] not exist.\n", member_if->name);
		ret = eRET_NOT_EXIST;
		break;

	case EBUSY:
		sysmgr_dbg("member interface [%s] already exist.\n", member_if->name);
		ret = eRET_ALREADY_EXIST;
		break;

	case ELOOP:
		sysmgr_dbg("member interface [%s] is bridge self.\n", member_if->name);
		ret = eRET_INVALID_ARG;
		break;

	default:
		sysmgr_err("br_add_interface() failed, err: %d,[%s]\n", rc, strerror(rc));
		ret = eRET_FAILURE;
		break;
	}

	close(sockfd);

	return (ret);

}

e_ret os_dep_del_bridge_member(tdp_if * dp_if, tdp_if * member_if)
{
	e_ret ret;
	int rc;
	int sockfd;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	rc = br_del_interface(sockfd, dp_if->name, member_if->name);
	switch (rc) {
	case 0:
		ret = eRET_SUCCESS;
		break;

	case ENODEV:
		sysmgr_dbg("member interface [%s] not exist.\n", member_if->name);
		ret = eRET_NOT_EXIST;
		break;

	case EINVAL:
		sysmgr_dbg("interface [%s] is NOT member of bridge[%s].\n", member_if->name, dp_if->name);
		ret = eRET_INVALID_ARG;
		break;

	default:
		sysmgr_err("br_del_interface() failed, err: %d,[%s]\n", rc, strerror(rc));
		ret = eRET_FAILURE;
		break;
	}

	close(sockfd);

	return (ret);

}

e_ret os_dep_if_up(const char *if_name)
{
	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", if_name);
	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	sysmgr_dbg("ioctl(%s, SIOCGIFFLAGS) == 0x%08X, rc: %d\n", if_name, ifr.ifr_flags, rc);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", if_name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	if ((ifr.ifr_flags & IFF_UP) != IFF_UP) {
		ifr.ifr_flags |= IFF_UP;
		rc = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
		sysmgr_dbg("ioctl(%s, SIOCSIFFLAGS, 0x%08X), rc: %d\n", if_name, ifr.ifr_flags, rc);
		if (rc < 0) {
			sysmgr_err("ioctl(%s, SIOCSIFFLAGS) failed, err: %d,[%s]\n", if_name, errno, strerror(errno));
			ret = eRET_FAILURE;
			goto out;
		}
	}
	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}

	return (ret);
}

e_ret os_dep_if_down(const char *if_name)
{
	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", if_name);
	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	sysmgr_dbg("ioctl(%s, SIOCGIFFLAGS) == 0x%08X, rc: %d\n", if_name, ifr.ifr_flags, rc);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", if_name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	if ((ifr.ifr_flags & IFF_UP) == IFF_UP) {
		ifr.ifr_flags &= ~IFF_UP;
		rc = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
		sysmgr_dbg("ioctl(%s, SIOCSIFFLAGS, 0x%08X), rc: %d\n", if_name, ifr.ifr_flags, rc);
		if (rc < 0) {
			sysmgr_err("ioctl(%s, SIOCSIFFLAGS) failed, err: %d,[%s]\n", if_name, errno, strerror(errno));
			ret = eRET_FAILURE;
			goto out;
		}
	}
	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}

	return (ret);
}

e_bool os_dep_is_valid_ip(const char *ipaddr)
{
	int ret = 0;
	struct in_addr inp;
	ret = inet_aton(ipaddr, &inp);
	if (ret == 0) {
		return eBOOL_FALSE;
	}

	return eBOOL_TRUE;
}

e_ret os_dep_set_if_mtu(const char *name, int mtu)
{
	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;

	if (mtu == 0) {
		/* TODO */
		return (eRET_SUCCESS);
	}

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", name);

	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	ifr.ifr_mtu = mtu;
	rc = ioctl(sockfd, SIOCSIFMTU, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCSIFMTU, %d) failed, err: %d,[%s]\n", name, mtu, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}

	return (ret);
}

e_ret os_dep_get_if_mtu(const char *name, int *mtu)
{
	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;

	*mtu = 0;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", name);

	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	rc = ioctl(sockfd, SIOCGIFMTU, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFMTU, %d) failed, err: %d,[%s]\n", name, *mtu, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	*mtu = ifr.ifr_mtu;
	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}

	return (ret);
}

e_ret os_dep_set_if_macaddr(const char *name, const char *macaddr)
{
	e_ret ret;
	int rc;
	int sockfd;
	unsigned char mac[6];
	unsigned int mac_sscan[6];
	struct ifreq ifr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", name);

	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	if ((ifr.ifr_flags & IFF_UP) == IFF_UP) {
		ifr.ifr_flags &= ~IFF_UP;
		rc = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
		sysmgr_dbg("ioctl(%s, SIOCSIFFLAGS, 0x%08X), rc: %d\n", name, ifr.ifr_flags, rc);
		if (rc < 0) {
			sysmgr_err("ioctl(%s, SIOCSIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
			ret = eRET_FAILURE;
			goto out;
		}
	}

	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
	sscanf(macaddr, "%02X:%02X:%02X:%02X:%02X:%02X", &mac_sscan[0], &mac_sscan[1], &mac_sscan[2],
	       &mac_sscan[3], &mac_sscan[4], &mac_sscan[5]);
	mac[0] = mac_sscan[0] & 0xFF;
	mac[1] = mac_sscan[1] & 0xFF;
	mac[2] = mac_sscan[2] & 0xFF;
	mac[3] = mac_sscan[3] & 0xFF;
	mac[4] = mac_sscan[4] & 0xFF;
	mac[5] = mac_sscan[5] & 0xFF;

	memcpy(&ifr.ifr_hwaddr.sa_data, mac, sizeof(mac));
	rc = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCSIFHWADDR, %s) failed, err: %d,[%s]\n", name, macaddr, errno,
			   strerror(errno));
		ret = eRET_FAILURE;
		ioctl(sockfd, SIOCGIFFLAGS, &ifr);
		ifr.ifr_flags |= IFF_UP;
		ioctl(sockfd, SIOCSIFFLAGS, &ifr);
		goto out;
	}

	ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	ifr.ifr_flags |= IFF_UP;
	rc = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
	sysmgr_dbg("ioctl(%s, SIOCSIFFLAGS, 0x%08X), rc: %d\n", name, ifr.ifr_flags, rc);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCSIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}

	return (ret);
}

e_ret os_dep_get_if_macaddr(const char *name, char *macaddr)
{
	e_ret ret;
	int rc;
	int sockfd;
	unsigned char mac[6];
	struct ifreq ifr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", name);

	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	rc = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFHWADDR, %s) failed, err: %d,[%s]\n", name, macaddr, errno,
			   strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	memcpy(mac, ifr.ifr_hwaddr.sa_data, sizeof(mac));
	sprintf(macaddr, "%02X:%02X:%02X:%02X:%02X:%02X", (unsigned char)mac[0], (unsigned char)mac[1],
		(unsigned char)mac[2], (unsigned char)mac[3], (unsigned char)mac[4], (unsigned char)mac[5]);
	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}

	return (ret);
}

e_ret os_dep_set_if_ipaddr(const char *name, const char *ipaddr)
{
	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;
	struct sockaddr_in sin;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", name);

	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	inet_aton(ipaddr, &sin.sin_addr);
	memcpy(&ifr.ifr_addr, &sin, sizeof(sin));
	rc = ioctl(sockfd, SIOCSIFADDR, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCSIFADDR, %s) failed, err: %d,[%s]\n", name, ipaddr, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}
	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}

	return (ret);
}

e_ret os_dep_get_if_ipaddr(const char *name, char *ipaddr)
{
	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;
	struct sockaddr_in *sin;
	char ipaddr_str[RC_IPV4_STR_MAX_SIZE];

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", name);

	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	rc = ioctl(sockfd, SIOCGIFADDR, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFADDR, %s) failed, err: %d,[%s]\n", name, ipaddr, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	sin = (struct sockaddr_in *)&ifr.ifr_addr;
	if (inet_ntop(AF_INET, &sin->sin_addr, ipaddr_str, sizeof(ipaddr_str)) != ipaddr_str) {
		sysmgr_err("inet_ntop() failed, err: %d,[%s]\n", errno, strerror(errno));
		ret = eRET_FAILURE;
	} else {
		strcpy(ipaddr, ipaddr_str);
		ret = eRET_SUCCESS;
	}

out:
	if (sockfd >= 0) {
		close(sockfd);
	}

	return (ret);
}

e_ret os_dep_set_if_netmask(const char *name, const char *netmask)
{
	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;
	struct sockaddr_in sin;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", name);
	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	inet_aton(netmask, &sin.sin_addr);
	memcpy(&ifr.ifr_addr, &sin, sizeof(sin));
	rc = ioctl(sockfd, SIOCSIFNETMASK, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCSIFNETMASK, %s) failed, err: %d,[%s]\n",
			   name, netmask, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}
	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}
	return (ret);
}

e_ret os_dep_get_if_netmask(const char *name, char *netmask)
{
	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;
	struct sockaddr_in *sin;
	char netmask_str[RC_IPV4_STR_MAX_SIZE];

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return eRET_FAILURE;
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s", name);
	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFFLAGS) failed, err: %d,[%s]\n", name, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	rc = ioctl(sockfd, SIOCGIFNETMASK, &ifr);
	if (rc < 0) {
		sysmgr_err("ioctl(%s, SIOCGIFNETMASK, %s) failed, err: %d,[%s]\n",
			   name, netmask, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	sin = (struct sockaddr_in *)&ifr.ifr_addr;
	if (inet_ntop(AF_INET, &(sin->sin_addr), netmask_str, sizeof(netmask_str)) != netmask_str) {
		sysmgr_err("inet_ntop() failed, err: %d,[%s]\n", errno, strerror(errno));
		ret = eRET_FAILURE;
	} else {
		strcpy(netmask, netmask_str);
		ret = eRET_SUCCESS;
	}

out:
	if (sockfd >= 0) {
		close(sockfd);
	}
	return (ret);
}

e_ret os_dep_change_default_gw(const char *defaultgw)
{

	e_ret ret;
	int rc;
	int sockfd;
	struct sockaddr_in sin;
	struct rtentry rt;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return (eRET_FAILURE);
	}

	/* Remove all default gw. */
	memset(&rt, 0, sizeof(struct rtentry));
	((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
	((struct sockaddr_in *)&rt.rt_gateway)->sin_family = AF_INET;
	((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
	rt.rt_flags = RTF_UP | RTF_GATEWAY;
	do {
		rc = ioctl(sockfd, SIOCDELRT, &rt);
	} while (rc == 0);

	/* Add new one. */
	sin.sin_family = AF_INET;
	sin.sin_port = 0;
	inet_aton(defaultgw, &sin.sin_addr);
	memcpy(&rt.rt_gateway, &sin, sizeof(struct sockaddr_in));
	((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
	((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
	rt.rt_flags = RTF_UP | RTF_GATEWAY;
	rc = ioctl(sockfd, SIOCADDRT, &rt);
	if (rc < 0) {
		sysmgr_err("ioctl(SIOCADDRT, %s) failed, err: %d,[%s]\n", defaultgw, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}
	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}
	return (rc);

}

e_ret os_dep_get_default_gw(char *defaultgw)
{
	/* TODO: get default gw */

	defaultgw[0] = 0;
	return (eRET_SUCCESS);
}

e_ret os_dep_update_name_server(const char *dns1, const char *dns2)
{
	e_ret ret;
	int rc;
	int resolvfd;
	const char *tmp;
	char nameserver_buf[32];

	if ((dns1 == NULL) || (dns1[0] == 0)) {
		tmp = dns2;
		dns2 = dns1;
		dns1 = tmp;
	}

	if ((dns1 == NULL) || (dns1[0] == 0) || (!os_dep_is_valid_ip(dns1))) {
		sysmgr_err("Invalid name server config dns1[%s], dns2[%s].\n", dns1, dns2);
		return eRET_INVALID_ARG;
	}

	resolvfd = open(RESOLV_CONF_FILE, O_CREAT | O_WRONLY | O_TRUNC | O_APPEND, 0666);
	if (resolvfd < 0) {
		sysmgr_err("open(%s) failed, err: %d,[%s]\n", RESOLV_CONF_FILE, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	rc = sprintf(nameserver_buf, "nameserver %s\n", dns1);
	write(resolvfd, nameserver_buf, rc);

	if ((dns2 != NULL) && (dns2[0] != 0) && (os_dep_is_valid_ip(dns2))) {
		rc = sprintf(nameserver_buf, "nameserver %s\n", dns2);
		write(resolvfd, nameserver_buf, rc);
	}

	ret = eRET_SUCCESS;

out:
	if (resolvfd >= 0) {
		close(resolvfd);
	}

	return (ret);
}

e_ret os_dep_get_name_server(char *dns1, char *dns2)
{

	e_ret ret;
	int rc;
	int resolvfd;
	e_bool got_line;
	char nameserver_buf[256];
	char *item_start, *item_end;
	char *line_start, *line_end, *buf_start, *buf_end;

	dns1[0] = 0;
	dns2[0] = 0;

	resolvfd = open(RESOLV_CONF_FILE, O_RDWR);
	if (resolvfd < 0) {
		sysmgr_err("open(%s) failed, err: %d,[%s]\n", RESOLV_CONF_FILE, errno, strerror(errno));
		return (eRET_NOT_EXIST);
	}

	rc = read(resolvfd, nameserver_buf, sizeof(nameserver_buf));
	if (rc < 0) {
		sysmgr_err("read(%s) failed, err: %d,[%s]\n", RESOLV_CONF_FILE, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	/* buffer get line init. */
	buf_start = nameserver_buf;
	buf_end = &buf_start[rc - 1];
	buf_get_line_init(line_start, line_end, buf_start);

	do {
		got_line = buf_get_line(line_start, line_end, buf_start, buf_end);
		//sysmgr_dbg("got_line[%c], line_start[%p], line_end[%p], buf_start[%p], buf_end[%p]\n",
		//      ((got_line) ? 'Y' : 'N'), line_start, line_end, buf_start, buf_end);
		if (got_line) {
			//sysmgr_dbg("line[%s]\n", line_start);
			if ((item_start = strstr(line_start, "nameserver ")) != NULL) {
				item_start += strlen("nameserver ");
				while (*item_start == ' ') {
					item_start++;
				}
				item_end = item_start;
				while ((*item_end == '.') || ((*item_end >= '0') && (*item_end <= '9'))) {
					item_end++;
				}
				*item_end = 0;
				if (item_end > item_start) {
					if (dns1[0] == 0) {
						strcpy(dns1, item_start);
					} else {
						strcpy(dns2, item_start);
						break;
					}
				}
			}
		} else {
			//sysmgr_dbg("buf_get_line() finish.\n");
			break;
		}
	} while (1);

	ret = eRET_SUCCESS;

	sysmgr_dbg("dns1[%s], dns2[%s]\n", dns1, dns2);

out:
	if (resolvfd >= 0) {
		close(resolvfd);
	}

	return (ret);

}

e_ret os_dep_add_vlan_if(tdp_if * dp_if, const char *base_if, const int vid)
{

	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;
	struct vlan_ioctl_args vlan_if_req;

	memset(&vlan_if_req, 0, sizeof(vlan_if_req));
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return (eRET_FAILURE);
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s.%d", base_if, vid);
	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc >= 0) {
		/* Already exist */
		ret = eRET_ALREADY_EXIST;
		goto out;
	}

	str_safe_cpy(vlan_if_req.device1, base_if, 23);
	vlan_if_req.u.VID = vid;
	vlan_if_req.cmd = ADD_VLAN_CMD;

	rc = ioctl(sockfd, SIOCSIFVLAN, &vlan_if_req);
	if (rc < 0) {
		sysmgr_err("ioctl(SIOCSIFVLAN, %s.%d) failed, err: %d,[%s]\n", base_if, vid, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}
	return (rc);

}

e_ret os_dep_del_vlan_if(tdp_if * dp_if, const char *base_if, const int vid)
{

	e_ret ret;
	int rc;
	int sockfd;
	struct ifreq ifr;
	struct vlan_ioctl_args vlan_if_req;

	memset(&vlan_if_req, 0, sizeof(vlan_if_req));
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return (eRET_FAILURE);
	}

	snprintf(ifr.ifr_name, (sizeof(ifr.ifr_name) - 1), "%s.%d", base_if, vid);
	rc = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
	if (rc < 0) {
		/* Not exist */
		ret = eRET_SUCCESS;
		goto out;
	}

	str_safe_cpy(vlan_if_req.device1, base_if, 23);
	vlan_if_req.u.VID = vid;
	vlan_if_req.cmd = DEL_VLAN_CMD;

	rc = ioctl(sockfd, SIOCSIFVLAN, &vlan_if_req);
	if (rc < 0) {
		sysmgr_err("ioctl(SIOCSIFVLAN, %s.%d) failed, err: %d,[%s]\n", base_if, vid, errno, strerror(errno));
		ret = eRET_FAILURE;
		goto out;
	}

	ret = eRET_SUCCESS;

out:
	if (sockfd >= 0) {
		close(sockfd);
	}
	return (rc);

}

e_ret os_dep_get_uptime(struct date_time * datetime)
{
	long uptime = 0;
	struct sysinfo s_info;

	if (0 == sysinfo(&s_info)) {
		uptime = s_info.uptime;
	}

	datetime->year = uptime / 31536000;
	datetime->month = (uptime % 31536000) / 2678400;
	datetime->day = (uptime % 2678400) / 86400;
	datetime->hour = (uptime % 86400) / 3600;
	datetime->minute = (uptime % 3600) / 60;
	datetime->second = uptime % 60;

	return (eRET_SUCCESS);
}

e_ret os_dep_get_datetime(struct date_time * datetime)
{

	time_t now;
	struct tm *now_tm;

	now = time(0);
	now_tm = localtime(&now);
	datetime->year = now_tm->tm_year + 1900;
	datetime->month = now_tm->tm_mon + 1;
	datetime->day = now_tm->tm_mday;
	datetime->hour = now_tm->tm_hour;
	datetime->minute = now_tm->tm_min;
	datetime->second = now_tm->tm_sec;

	return (eRET_SUCCESS);
}

e_ret os_dep_set_datetime(struct date_time * datetime)
{
	int rc;
	struct tm time_tm;
	struct timeval time_tv;
	time_t timep;

	time_tm.tm_year = datetime->year - 1900;
	time_tm.tm_mon = datetime->month - 1;
	time_tm.tm_mday = datetime->day;
	time_tm.tm_hour = datetime->hour;
	time_tm.tm_min = datetime->minute;
	time_tm.tm_sec = datetime->second;
	time_tm.tm_wday = 0;
	time_tm.tm_yday = 0;
	time_tm.tm_isdst = 0;

	timep = mktime(&time_tm);
	time_tv.tv_sec = timep;
	time_tv.tv_usec = 0;

	rc = settimeofday(&time_tv, NULL);
	if (rc < 0) {
		sysmgr_err("settimeofday err: %d,[%s]\n", errno, strerror(errno));
		return (eRET_FAILURE);
	}

	return (eRET_SUCCESS);
}

e_ret os_dep_get_if_link(const char *name, e_bool *link)
{

	int rc;
	int sockfd;
	struct ifreq ifr;
	struct ethtool_value edata;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		sysmgr_err("socket() failed, err: %d,[%s]\n", errno, strerror(errno));
		return (eRET_FAILURE);
	}

	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_name, name);

	edata.cmd = ETHTOOL_GLINK;
	ifr.ifr_data = (caddr_t)&edata;
	rc = ioctl(sockfd, SIOCETHTOOL, &ifr);
	if (rc < 0) {
		*link = eBOOL_FALSE;
		close (sockfd);
		return (eRET_FAILURE);
	}

	*link = edata.data ? eBOOL_TRUE : eBOOL_FALSE;

	close (sockfd);
	return (eRET_SUCCESS);

}

